﻿using System;
using System.Collections.Generic;
using Netbits.Common.Conditions;
using Netbits.Common.Threading;

namespace Netbits.Common.Collections
{
	/// <summary>
	/// Represents a Locked Queue-Extended
	/// </summary>
	/// <typeparam name="TItem">Type of the items</typeparam>
	public class LockedQueueExtended<TItem> : QueueExtended<TItem>
	{
		#region Private Variables

		/// <summary>
		/// The Lock Object.
		/// </summary>
		protected Lock _Lock;
		bool _ExternalLock;
		bool _Disposed;

		#endregion

		#region Constructor

		/// <summary>
		/// Create a new instance of the LockedQueueExtended
		/// </summary>
		public LockedQueueExtended() : this( new Lock( true ) )
		{
			_ExternalLock = false;
		}

		/// <summary>
		/// Create a new instance of the LockedQueueExtended with specified Lock instance
		/// </summary>
		/// <param name="Lock_">The lock instance</param>
		public LockedQueueExtended( Lock Lock_ ) : base()
		{
			Condition.Requires( Lock_, "Lock_" ).IsNotNull();
			_Lock = Lock_;
			_ExternalLock = true;
		}

		/// <summary>
		/// Create a new instance of the LockedQueueExtended that contains items copied from the specified
		/// Collection.
		/// </summary>
		/// <param name="Collection_">The collection whose items are copied to the new LockedQueueExtended</param>
		public LockedQueueExtended( IEnumerable<TItem> Collection_ ) : this( Collection_, new Lock( true ) )
		{
			_ExternalLock = false;
		}

		/// <summary>
		/// Create a new instance of the LockedQueueExtended that contains items copied from the specified
		/// Collection an with specified Lock instance
		/// </summary>
		/// <param name="Collection_">The collection whose items are copied to the new LockedQueueExtended</param>
		/// <param name="Lock_">The lock instance</param>
		public LockedQueueExtended( IEnumerable<TItem> Collection_, Lock Lock_ ) : base( Collection_ )
		{
			Condition.Requires( Lock_, "Lock_" ).IsNotNull();
			_Lock = Lock_;
			_ExternalLock = true;
		}

		/// <summary>
		/// Create a new instance of the LockedQueueExtended that has the specified initial capacity
		/// </summary>
		/// <param name="Capacity_">The initial number of items that the queue can contain</param>
		public LockedQueueExtended( int Capacity_ ) : this( Capacity_, new Lock( true ) )
		{
			_ExternalLock = false;
		}

		/// <summary>
		/// Create a new instance of the LockedQueueExtended that has the specified initial capacity and
		/// the use the specified Lock instance
		/// </summary>
		/// <param name="Capacity_">The initial number of items that the queue can contain</param>
		/// <param name="Lock_">The lock instance.</param>
		public LockedQueueExtended( int Capacity_, Lock Lock_ ) : base( Capacity_ )
		{
			Condition.Requires( Lock_, "Lock_" ).IsNotNull();
			_Lock = Lock_;
			_ExternalLock = true;
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Returns the lock-object.
		/// </summary>
		public Lock SyncObject
		{
			get
			{
				return _Lock;
			}
		}

		#endregion

		#region Overrides

		/// <summary>
		/// Clears all items from the queue
		/// </summary>
		protected override void __ClearAllItems()
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__ClearAllItems();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Removes and returns the item at the beginning of the queue
		/// </summary>
		/// <returns>The item that is removed from the beginning of the queue</returns>
		protected override TItem __DequeueItem()
		{
			try
			{
				_Lock.EnterWriteLock();
				return base.__DequeueItem();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Adds an item to the end of the queue
		/// </summary>
		/// <param name="Item_">The item to add to the queue.</param>
		protected override void __EnqueueItem( TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__EnqueueItem( Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Returns the item at the beginning of the queue.
		/// </summary>
		/// <returns>The item at the beginning of the queue</returns>
		protected override TItem __PeekItem()
		{
			try
			{
				_Lock.EnterReadLock();
				return base.__PeekItem();
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Copies the queue items to a new array
		/// </summary>
		/// <returns>A new array containing item copied from the queue</returns>
		protected override TItem[] __ToArray()
		{
			try
			{
				_Lock.EnterReadLock();
				return base.__ToArray();
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Set the capacity to the actual number of items.
		/// </summary>
		protected override void __TrimExcess()
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__TrimExcess();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Determines whether the specified item is in the list
		/// </summary>
		/// <param name="Item_">The item to check</param>
		/// <returns>true if the item is in the queue, otherwise false</returns>
		public override bool Contains( TItem Item_ )
		{
			try
			{
				_Lock.EnterReadLock();
				return base.Contains( Item_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Return the number of items in the queue
		/// </summary>
		public override int Count
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return base.Count;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
		}

		/// <summary>
		/// Get new enumerator for this queue
		/// </summary>
		/// <returns>The new enumerator</returns>
		public override IEnumerator<TItem> GetEnumerator()
		{
			return new LockedEnumerator<TItem>( this, _Lock );
		}

		/// <summary>
		/// Dispose this queue and the lock instance.
		/// </summary>
		/// <param name="Disposing_">Dispose managed resources</param>
		protected override void Dispose( bool Disposing_ )
		{
			if( !_Disposed )
			{
				if( _Lock != null && !_ExternalLock )
				{
					_Lock.Dispose();
					_Lock = null;
				}

				_Disposed = true;
			}

			base.Dispose( Disposing_ );
		}

		#endregion
	}
}
